package com.atguigu.gateway.predicate;

import org.springframework.util.StringUtils;
import jakarta.validation.constraints.NotEmpty;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.GatewayPredicate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;

import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
/**
 * VIP路由谓词工厂类，用于在Spring Cloud Gateway中根据请求参数判断是否为VIP用户
 * 以确定请求的路由
 */
@Component
public class VipRoutePredicateFactory extends AbstractRoutePredicateFactory<VipRoutePredicateFactory.Config> {

    /**
     * 构造函数，初始化父类
     */
    public VipRoutePredicateFactory() {
        super(Config.class);
    }

    /**
     * 根据配置参数构建一个谓词，用于判断请求是否符合VIP路由条件
     *
     * @param config 配置参数，包含判断所需的参数名和期望值
     * @return 返回一个谓词，该谓词在请求参数与配置的参数名和期望值匹配时返回true
     */
    @Override
    public Predicate<ServerWebExchange> apply(Config config) {
        return new GatewayPredicate() {
            /**
             * 判断请求是否符合VIP条件
             *
             * @param serverWebExchange 服务器与客户端之间的交换信息
             * @return 如果请求参数中包含配置的参数名且值与期望值相等，则返回true
             */
            @Override
            public boolean test(ServerWebExchange serverWebExchange) {
                ServerHttpRequest request = serverWebExchange.getRequest();
                String first = request.getQueryParams().getFirst(config.param);
                return StringUtils.hasText(first) && first.equals(config.value);
            }
        };
    }

    /**
     * 定义配置参数的快捷字段顺序，用于简化配置
     *
     * @return 返回配置参数的列表，按顺序排列
     */
    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("param", "value");
    }

    /**
     * 配置类，用于定义和验证路由谓词所需的参数
     */
    @Validated
    public static class Config {
        @NotEmpty
        private String param;
        @NotEmpty
        private String value;

        /**
         * 获取参数名
         *
         * @return 参数名
         */
        public @NotEmpty String getParam() {
            return param;
        }

        /**
         * 设置参数名
         *
         * @param param 参数名
         */
        public void setParam(@NotEmpty String param) {
            this.param = param;
        }

        /**
         * 获取期望值
         *
         * @return 期望值
         */
        public @NotEmpty String getValue() {
            return value;
        }

        /**
         * 设置期望值
         *
         * @param value 期望值
         */
        public void setValue(@NotEmpty String value) {
            this.value = value;
        }
    }

}
